﻿#region

using System;
using System.Collections.Generic;
using System.Deployment.Application;
using System.Diagnostics;
using System.Drawing;
using System.Net.Configuration;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using FRS.Devices;
using FRS.Properties;

#endregion

namespace FRS
{
    public partial class TrayForm : Form
    {
        private readonly List<SwitchBox> sb_devices = new List<SwitchBox>();
        private readonly List<CECC> cecc_devices = new List<CECC>();
        private readonly List<NETIO_230B> netio_230b_devices = new List<NETIO_230B>();
        private bool running = true;
        private Thread aliveCheckThread;
        private readonly DeviceList settings;
        private readonly PersistentSettings data;

        public TrayForm()
        {
            InitializeComponent();
            //SetAllowUnsafeHeaderParsing20();

            if (ApplicationDeployment.IsNetworkDeployed)
            {
                Version myVersion = ApplicationDeployment.CurrentDeployment.CurrentVersion;
                lblVersion.Text = string.Format("Version: v{0}.{1}.{2}.{3}", myVersion.Major, myVersion.Minor, myVersion.Build, myVersion.Revision);
            }

            data = FileManager.ReadSettingsListFile();
            
            foreach (Device device in FileManager.SwitchBox_ReadDeviceListFile())
                sb_devices.Add(new SwitchBox(device));

            foreach (Device device in FileManager.CECC_ReadDeviceListFile())
                cecc_devices.Add(new CECC(device));

            foreach (Device device in FileManager.NETIO_230B_ReadDeviceListFile())
                netio_230b_devices.Add(new NETIO_230B(device));

            UpdateDeviceNames();

            treeView1.AfterCheck += treeView1_AfterCheck;

            settings = new DeviceList(sb_devices, cecc_devices, netio_230b_devices, data);
            settings.FormHidden += settings_FormHidden;
        }

        void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
        {
            if (e.Action == TreeViewAction.Unknown) return;

            OutputTreeNode devicenode = e.Node as OutputTreeNode;

            if (devicenode != null)
            {
                devicenode.Device.SetOutput(devicenode.OutputNr, devicenode.Checked ? 1 : 0);
            }
        }

        protected override void OnActivated(EventArgs e)
        {
            base.OnActivated(e);

            foreach (CECC device in cecc_devices)
                device.RefreshTreeNodes();
            
            foreach (SwitchBox device in sb_devices)
                device.RefreshTreeNodes();
        
            foreach (NETIO_230B device in netio_230b_devices)
                device.RefreshTreeNodes();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            foreach (CECC device in cecc_devices)
                device.UpdateValues = true;

            foreach (SwitchBox device in sb_devices)
                device.UpdateValues = true;
            
            foreach (NETIO_230B device in netio_230b_devices)
                device.UpdateValues = true;
            
            StartDeviceRefresh();
            AddDeviceMenuItems();
            AddDeviceTreeNodes();

            aliveCheckThread = new Thread(AliveCheckThreadFunction);
            aliveCheckThread.Start();
        }

        public void AliveCheckThreadFunction()
        {
            while (running)
            {
                try
                {
                    AliveCheck();

                    Thread.Sleep(1000);
                }
                catch (ThreadAbortException)
                {
                    Thread.ResetAbort();
                }
                
            }
        }

        private void AliveCheck()
        {
            Icon icon = Resources.trayicon_yellow;

            bool allAlive = true;
            bool allDead = true;

            foreach (CECC ceccDevice in cecc_devices)
                if (ceccDevice.IsAlive) allDead = false;
                else allAlive = false;

            foreach (SwitchBox sbDevice in sb_devices)
                if (sbDevice.IsAlive) allDead = false;
                else allAlive = false;

            foreach (NETIO_230B netio_23bDevice in netio_230b_devices)
                if (netio_23bDevice.IsAlive) allDead = false;
                else allAlive = false;
            
            if (allAlive)
                icon = Resources.trayicon;
            if (allDead)
                icon = Resources.trayicon_red;

            notifyIcon1.Icon = icon;
        }

        private void AddDeviceMenuItems()
        {
            foreach (CECC device in cecc_devices)
                contextMenuStrip1.Items.Insert(0, device.RootMenuItem);

            foreach (SwitchBox device in sb_devices)
                contextMenuStrip1.Items.Insert(0, device.RootMenuItem);

            foreach (NETIO_230B device in netio_230b_devices)
                contextMenuStrip1.Items.Insert(0, device.RootMenuItem);
        }

        private void AddDeviceTreeNodes()
        {
            foreach (CECC device in cecc_devices)
                treeView1.Nodes.Add(device.RootNode);

            foreach (SwitchBox device in sb_devices)
                treeView1.Nodes.Add(device.RootNode);

            foreach (NETIO_230B device in netio_230b_devices)
                treeView1.Nodes.Add(device.RootNode);

            treeView1.ExpandAll();
        }

        private void RemoveDeviceMenuItems()
        {
            foreach (CECC device in cecc_devices)
                contextMenuStrip1.Items.Remove(device.RootMenuItem);

            foreach (SwitchBox device in sb_devices)
                contextMenuStrip1.Items.Remove(device.RootMenuItem);
        
            foreach (NETIO_230B device in netio_230b_devices)
                contextMenuStrip1.Items.Remove(device.RootMenuItem);
        }

        private void RemoveDeviceTreeNodes()
        {
            foreach (CECC device in cecc_devices)
                treeView1.Nodes.Remove(device.RootNode);

            foreach (SwitchBox device in sb_devices)
                treeView1.Nodes.Remove(device.RootNode);

            foreach (NETIO_230B device in netio_230b_devices)
                treeView1.Nodes.Remove(device.RootNode);
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                ShowInTaskbar = false;
                //notifyIcon1.Visible = true;
                Hide();
            }
            else if (WindowState == FormWindowState.Normal)
            {
                ShowInTaskbar = true;
                treeView1.ExpandAll();
                //notifyIcon1.Visible = false;
            }
        }

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (WindowState == FormWindowState.Normal)
            {
                Activate();
            }
            else
            {
                Show();
                Debug.WriteLine("WindowsState = {0}", WindowState);
                WindowState = FormWindowState.Normal;
            }
        }

        public static bool SetAllowUnsafeHeaderParsing20()
        {
            //Get the assembly that contains the internal class
            Assembly aNetAssembly = Assembly.GetAssembly(typeof (SettingsSection));
            if (aNetAssembly != null)
            {
                //Use the assembly in order to get the internal type for the internal class
                Type aSettingsType = aNetAssembly.GetType("System.Net.Configuration.SettingsSectionInternal");
                if (aSettingsType != null)
                {
                    //Use the internal static property to get an instance of the internal settings class.
                    //If the static instance isn't created allready the property will create it for us.
                    object anInstance = aSettingsType.InvokeMember("Section",
                                                                   BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null, new object[] {});

                    if (anInstance != null)
                    {
                        //Locate the private bool field that tells the framework is unsafe header parsing should be allowed or not
                        FieldInfo aUseUnsafeHeaderParsing = aSettingsType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance);
                        if (aUseUnsafeHeaderParsing != null)
                        {
                            aUseUnsafeHeaderParsing.SetValue(anInstance, true);
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StopDeviceRefresh();

            running = false;
            aliveCheckThread.Abort();
            aliveCheckThread.Join();

            Close();
        }

        private void StopDeviceRefresh ()
        {
            foreach (CECC device in cecc_devices)
            {
                device.StopRefresh();
                //ceccDevice.OnOutputValuesChanged -= device_OnOutputValuesChanged;
            }
            foreach (SwitchBox device in sb_devices)
            {
                device.StopRefresh();
                //sbDevice.OnOutputValuesChanged -= device_OnOutputValuesChanged;
            }
            foreach (NETIO_230B device in netio_230b_devices)
            {
                device.StopRefresh();
                //sbDevice.OnOutputValuesChanged -= device_OnOutputValuesChanged;
            }
        }

        private void StartDeviceRefresh()
        {
            foreach (CECC device in cecc_devices)
            {
                device.StartRefresh();
                //ceccDevice.OnOutputValuesChanged += device_OnOutputValuesChanged;
            }
            foreach (SwitchBox device in sb_devices)
            {
                device.StartRefresh();
                //sbDevice.OnOutputValuesChanged += device_OnOutputValuesChanged;
            }
            foreach (NETIO_230B device in netio_230b_devices)
            {
                device.StartRefresh();
                //sbDevice.OnOutputValuesChanged += device_OnOutputValuesChanged;
            }
        }
        
        //void device_OnOutputValuesChanged(object sender, DeviceBase.OutputValuesChangedArgs e)
        //{
        //    if (data.DoNotShowNotification) return;

        //    if (!e.Device.IsAlive) return;
            
        //    Invoke((MethodInvoker)delegate
        //    {
        //        notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
        //        notifyIcon1.BalloonTipTitle = String.Format("{0}:", e.Device.Name);

        //        StringBuilder builder = new StringBuilder();

        //        for (int i = 0; i < e.Device.OutputNames.Count; i++)
        //            if (((e.Mask >> i) & 0x01) != 0) 
        //                builder.Append(String.Format("{0}: {1} -> {2}\n", i, e.Device.OutputNames[i], ((e.Value >> i) & 0x01) > 0 ? "on" : "off"));

        //        notifyIcon1.BalloonTipText = builder.ToString();

        //        notifyIcon1.ShowBalloonTip(3000);
        //    });
        //}

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            StopDeviceRefresh();
            
            RemoveDeviceMenuItems();
            RemoveDeviceTreeNodes();

            settings.Show();
        }


        void settings_FormHidden(object sender, EventArgs e)
        {
            foreach (CECC device in cecc_devices)
                device.UpdateValues = true;

            foreach (SwitchBox device in sb_devices)
                device.UpdateValues = true;

            foreach (NETIO_230B device in netio_230b_devices)
                device.UpdateValues = true;

            AddDeviceMenuItems();
            AddDeviceTreeNodes();
            StartDeviceRefresh();

            UpdateDeviceNames();
        }

        private void TrayForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            StopDeviceRefresh();
            running = false;
            aliveCheckThread.Abort();
            aliveCheckThread.Join();
        }

        private void treeView1_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            OutputTreeNode deviceNode = e.Node as OutputTreeNode;

            if (deviceNode != null)
            {
                /* root node */
                if (deviceNode.Parent == null)
                    deviceNode.Device.Name = e.Label;
                /* output node */
                if (deviceNode.OutputNr != -1)
                    deviceNode.Device.SetOutputName(deviceNode.OutputNr, e.Label);
            }
        }

        void UpdateDeviceNames()
        {
            foreach (CECC device in cecc_devices)
                device.UpdateNames = true;
            foreach (SwitchBox device in sb_devices)
                device.UpdateNames = true;
            foreach (NETIO_230B device in netio_230b_devices)
                device.UpdateNames = true;
        }

        private void treeView1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F2)
            {
                if (treeView1.SelectedNode != null)
                    treeView1.SelectedNode.BeginEdit();
            }
        }
    }
}